#include "game_file.h"
#include "game_macros.h"
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <algorithm>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/fcntl.h>

BOOL __is_directory_exist(const std::string& path){
  struct stat st;

  if((stat(path.c_str(), &st) == 0) && S_ISDIR(st.st_mode))
    return TRUE;

  return FALSE;
}

BOOL __is_file_exist(const std::string& path){
  struct stat st;

  if((stat(path.c_str(), &st) == 0) && S_ISREG(st.st_mode))
    return TRUE;

  return FALSE;
}

std::string __get_file_extension(std::string &filename)
{
  std::string fileExtension;
  size_t pos = filename.find_last_of('.');
  if (pos != std::string::npos)
  {
    fileExtension = filename.substr(pos, filename.length());

    std::transform(fileExtension.begin(), fileExtension.end(), fileExtension.begin(), ::tolower);
  }

  return fileExtension;
}

bool __file_extension_filter(const std::string& file_path, const std::vector<std::string> &allow_list)
{
  // 转换成小写，再判断后缀名
  std::string tmp = file_path;
  transform(file_path.begin(),file_path.end(),tmp.begin(),::tolower);

  for (const auto& extension : allow_list) {
    if (tmp.size() >= extension.size() &&
      tmp.compare(tmp.size() - extension.size(), extension.size(), extension) == 0) {
      return true;
    }
  }
  return false;
}

BOOL __is_absolute_path(const std::string &path)
{
  return path[0] == '/' ? TRUE : FALSE;
}

char *__getcwd(char *dest, size_t len)
{
  return getcwd(dest, len);
}

size_t __get_string_from_file(std::string &str, const char *filename)
{
  do
  {
    ::FILE *fp = ::fopen(filename, "rb");

    CC_BREAK_IF_LOG(NULL == fp, "could not open file %s with [%d]%s\n", filename, errno, strerror(errno));

    ::fseek(fp, 0, SEEK_END);
    size_t sz = ::ftell(fp);
    str.clear();
    // str.resize(sz);

    if (sz)
    {
      ::rewind(fp);
      char buff[1024];
      size_t n;
      // for(size_t ret = 0;ret ; ::fread(buff,1024,fp))
      // size_t ret = ::fread(str.append, 1, v->size(), fp);
      // C4_CHECK(ret == (size_t)sz);

      while (0 < (n = ::fread(buff, 1, 1024, fp)))
      {
        str.append(buff, n);
        // str.
        // __log("data is %s\n",buff);
      }
    }
    ::fclose(fp);

    return sz;

  } while (true);

  return -1;
}

BOOL __write_string_to_file(std::string& str, const std::string &filename)
{
  do {
    FILE *fp = fopen(filename.c_str(),"w");
    CC_BREAK_IF_LOG(NULL == fp, "%s: open %s failed", __func__, filename.c_str());
    fwrite(str.c_str(), str.size(), 1, fp);
    fclose(fp);
    __fsync(filename);
    return TRUE;
  }while(true);
  return FALSE;
}

int __mkdir(const std::string& dest,__mode_t mode){
  printf("__mkdir:%s\n",dest.c_str());
  int ret = mkdir(dest.c_str(),mode);
  return ret;
}

int __mkdir(const std::string& dest){
  return __mkdir(dest,S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH );
}

int __mkdirs(const std::string& dest){

  int ret = -1;
  do{
    std::string dir;
    size_t pos;
    size_t last;
    if(__is_absolute_path(dest)){
      pos = dest.find_first_of('/',1);
      dir = "/";
      last = 1;
    }else{
      pos = dest.find_first_of('/');
      last = 0;
    }

    do{
      if(pos == std::string::npos){
        pos = dest.size();
      }

      dir.append(dest.substr(last,pos - last));
      last = pos;
      pos = dest.find_first_of('/',pos + 1);
      if(!__is_directory_exist(dir) && 0 != (ret =__mkdir(dir.c_str()))){
        // printf("errno=%d,%s\n",errno,strerror(errno));
        C_WARN("__mkdirs(%s) with Warning : [%d]%s\n",dest.c_str(),errno,strerror(errno));
        return ret;
      }


    }while(last < dest.size());


    return 0;
  }while(true);

  return ret;
}

std::string __get_file_parent(std::string filename){
  std::string str;
  size_t pos = filename.find_last_of('/');
  if (pos != std::string::npos)
  {
    str = filename.substr(0,pos);
  }

  return str;
}

BOOL __get_filenames_from_path(std::string path, std::vector<std::string> &filenames)
{
  DIR *pDir;
  struct dirent *ptr;
  if (!(pDir = opendir(path.c_str())))
  {
    return FALSE;
  }
  while ((ptr = readdir(pDir)) != 0)
  {
    if (strcmp(ptr->d_name, ".") != 0 && strcmp(ptr->d_name, "..") != 0)
    {
      filenames.push_back(path + "/" + ptr->d_name);
    }
  }
  closedir(pDir);
  return TRUE;
}

BOOL __remove_file(const std::string& path)
{
  return 0 == ::remove(path.c_str());
}

BOOL __copy_file(const std::string& src, const std::string& dest)
{
  char buffer[BUFSIZ];
  size_t n;
  FILE *f1 = fopen(src.c_str(), "r");
  FILE *f2 = fopen(dest.c_str(), "w");
  BOOL done = FALSE;
  if ((NULL == f1) || (NULL == f2)) {
    goto exit;
  }

  while ((n = fread(buffer, sizeof(char), sizeof(buffer), f1)) > 0) {
    if (fwrite(buffer, sizeof(char), n, f2) != n) {
      break;
    }
  }
  done = TRUE;

  exit:
  if (f1 != NULL) {
    fclose(f1);
  }
  if (f2 != NULL) {
    fclose(f2);
  }
  return done;
}

BOOL __move_file(const std::string& src, const std::string& dest)
{
  return ::rename(src.c_str(), dest.c_str());
}

BOOL __fsync(const std::string &path)
{
  int fd = open(path.c_str(), O_RDONLY);
  if (fd < 0) {
    return FALSE;
  }
  int ret = fsync(fd);
  close(fd);
  return (0 == ret) ? TRUE : FALSE;
}
